//@author A0102127Y
#ifndef CMDPARSER_H
#define CMDPARSER_H

#include <sstream>
#include <string>
#include <ctime>
#include <vector>
#include <regex>
#include "CommonObjects.h"
#include "AllCmds.h"

namespace Twentyfifth {

	static const int MAX_NUM_DIGIT = 31;

	static const int CONST_ZERO = 0;
	static const int CONST_ONE_HUNDRED = 100;
	static const int CONST_ONE_THOUSAND = 1000;

	static const int DAY_INVALID = -1;
	static const int DAY_NEXT = 1;
	static const int DAY_NEXT_WEEK = 7;
	static const int DAY_WEEK_FIRST = 0;
	static const int DAY_WEEK_SECOND = 1;
	static const int DAY_WEEK_THIRD = 2;
	static const int DAY_WEEK_FOURTH = 3;
	static const int DAY_WEEK_FIFTH = 4;
	static const int DAY_WEEK_SIXTH = 5;
	static const int DAY_WEEK_SEVENTH = 6;

	static const int TIME_TWELVE = 12;
	static const int TIME_NEXT_HOUR = 1;

	static const int DEFAULT_HOUR_LENGTH = 2;
	static const int DEFAULT_MINUTE_LENGTH = 2;
	static const int DEFAULT_TIME_LENGTH = 4;
	static const int DEFAULT_INVALID_TIME = -1;
	static const int DEFAULT_DATE_LENGTH = 10;

	static const int DEFAULT_CMONTH_CONST = 1;
	static const int DEFAULT_CYEAR_CONST = 1900;

	static const int DELIMITER_INVALID_INDEX = -1;
	static const int INDEX_ZERO = 0;
	static const int INDEX_FIRST = 1;
	static const int INDEX_SECOND = 2;
	static const int INDEX_THIRD = 3;
	static const int INDEX_SIXTH = 6;

	static const char DELIMITER_SPACE = ' ';
	static const char DELIMITER_DASH = '-';
	static const char DELIMITER_ENDCHAR = '\0';

	static const std::string STRING_SINGLE_SPACE = " ";
	static const std::string STRING_SINGLE_DASH = "-";

	static const std::string INVALID_LOCALTIME = "Invalid argument to _localtime64_s";
	static const std::string INVALID_TASKID = "Invalid task ID";

	static const std::string ERROR_TIME = "Invalid time entered";

	static const std::string ATTRIB_DESCRIPTION = "-description";
	static const std::string ATTRIB_START = "-start";
	static const std::string ATTRIB_END = "-end";
	static const std::string ATTRIB_DEADLINE = "-deadline";
	static const std::string ATTRIB_VENUE = "-venue";

	static const std::string ATTRIB_ADD_DESCRIPTION = "description";
	static const std::string ATTRIB_ADD_START = "start";
	static const std::string ATTRIB_ADD_END = "end";
	static const std::string ATTRIB_ADD_DEADLINE = "deadline";
	static const std::string ATTRIB_ADD_VENUE = "venue";

	static const std::string ATTRIB_EDIT_STARTTIME = "-start-time";
	static const std::string ATTRIB_EDIT_ENDTIME = "-end-time";
	static const std::string ATTRIB_EDIT_DEADLINETIME = "-deadline-time";
	static const std::string ATTRIB_EDIT_STARTDATE = "-start-date";
	static const std::string ATTRIB_EDIT_ENDDATE = "-end-date";
	static const std::string ATTRIB_EDIT_DEADLINEDATE = "-deadline-date";

	static const std::string TYPE_TIMED_TASK = "TIMED_TASK";
	static const std::string TYPE_DEADLINE_TASK = "DEADLINE_TASK";
	static const std::string TYPE_FLOATING_TASK = "TASK";
	static const std::string TYPE_QUERY = "QUERY";
	static const std::string TYPE_INVALID = "INVALID";

	static const std::string CMD_ADD = "add";
	static const std::string CMD_EDIT = "edit";
	static const std::string CMD_VIEW = "view";
	static const std::string CMD_SEARCH = "search";
	static const std::string CMD_UNDO = "undo";
	static const std::string CMD_DELETE = "delete";
	static const std::string CMD_MARK = "mark";
	static const std::string CMD_GCAL = "gcal";
	static const std::string CMD_EXIT = "exit";

	static const std::string TIME_DEFAULT = "0800";

	static const std::string TODAY_SHORT = "tdy";
	static const std::string TODAY_LONG = "today";
	static const std::string TMR_SHORT = "tmr";
	static const std::string TMR_LONG = "tomorrow";

	static const std::string SUNDAY_LONG = "sunday";
	static const std::string MONDAY_LONG = "monday";
	static const std::string TUESDAY_LONG = "tuesday";
	static const std::string WEDNESDAY_LONG = "wednesday";
	static const std::string THURSDAY_LONG = "thursday";
	static const std::string FRIDAY_LONG = "friday";
	static const std::string SATURDAY_LONG = "saturday";

	static const std::string SUNDAY_SHORT = "sun";
	static const std::string MONDAY_SHORT = "mon";
	static const std::string TUESDAY_SHORT = "tue";
	static const std::string WEDNESDAY_SHORT = "wed";
	static const std::string THURSDAY_SHORT = "thu";
	static const std::string FRIDAY_SHORT = "fri";
	static const std::string SATURDAY_SHORT = "sat";

	static const std::string STATUS_DONE = "done";
	static const std::string STATUS_UNDONE = "undone";

	class Parser {
	private:
		static const std::regex REGEX_DATE;
		static const std::regex REGEX_TIME_LONG;
		static const std::regex REGEX_TIME_NO_MINUTES;
		static const std::regex REGEX_TIME_24HR;
		static const std::regex REGEX_TIME_24HR_NO_MINUTES;
		static const std::string SUFFIX_PM;
		static const std::string SUFFIX_AM;
		bool isAllDigit(std::string input);
		bool isAllAlpha(std::string input);
		static std::string convertToLowerCase(std::string input);

		struct tm getCurrTime();
		int getDayOfTheWeek(std::string input);
		int getDigitsCount(std::string input);

		std::vector<int> timeParse(std::string time);
		std::vector<int> dateParse(std::string date);
		std::vector<int> dayParse(std::string date);
		DateTime dateAndTimeParse(std::string time, std::string date);
		void startParse(std::string input, Task &result);
		void endParse(std::string input, Task &result);
		void checkAndSetEndParse(Task &result);
		void deadlineParse(std::string input, Task &result);
		void venueParse(std::string word, Task &result);
		void descriptionParse(std::string word, Task &result);
		void optionParse(std::string input, std::string optionType, Task &result);
		CmdAdd addParse(std::istringstream &istream);
		CmdDel deleteParse(std::istringstream &istream);
		CmdMark markParse(std::istringstream &istream);
		CmdEdit editParse(std::istringstream &istream);
		CmdSearch searchParse(std::istringstream &istream);
		CmdView viewParse(std::istringstream &istream);
		CmdGCal gcalParse(std::istringstream &istream);

		std::string getFirstWord(std::string);
		std::string removeFirstWord(std::string);
		int getSpaceAfterFirstWord(std::string);

	public:
		static Cmd::CmdType identifyCmdType(std::string);

		Cmd* parse(std::string userInput);

	};
}

#endif